home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 5 / Skunkware 5.iso / src / Tools / lynx-2.4 / utils / inews / clientlib.c next >
Encoding:
C/C++ Source or Header  |  1995-06-28  |  11.1 KB  |  536 lines

  1. #ifndef lint
  2. static char    *sccsid = "@(#)clientlib.c    1.11    (Berkeley) 10/27/89";
  3. #endif
  4.  
  5. /*
  6.  * NNTP client routines.
  7.  */
  8.  
  9. /*
  10.  * Include configuration parameters only if we're made in the nntp tree.
  11.  */
  12.  
  13. #ifdef FOR_NN
  14. #include "conf.h"
  15. #endif
  16.  
  17. #ifdef NNTPSRC
  18. #include "../config.h"
  19. #endif NNTPSRC
  20.  
  21. #include <stdio.h>
  22. #ifndef FOR_NN
  23. #include <sys/types.h>
  24. #endif
  25. #include <sys/socket.h>
  26. #ifdef FOR_NN
  27. #if !defined(NETWORK_DATABASE) || defined(NETWORK_BYTE_ORDER)
  28. #include <netinet/in.h>
  29. #endif
  30. #else
  31. #include <netinet/in.h>
  32. #endif
  33. #ifndef EXCELAN
  34. # include <netdb.h>
  35. #endif not EXCELAN
  36.  
  37. #ifndef FOR_NN
  38. #ifdef USG
  39. # define    index    strchr
  40. # define        bcopy(a,b,c)   memcpy(b,a,c)
  41. # define        bzero(a,b)     memset(a,'\0',b)
  42. #endif USG
  43. #endif
  44.  
  45. #ifdef EXCELAN
  46. # define    IPPORT_NNTP    119
  47. #endif
  48.  
  49. #ifdef DECNET
  50. #include <netdnet/dn.h>
  51. #include <netdnet/dnetdb.h>
  52. #endif DECNET
  53.  
  54. #include "nntp.h"
  55.  
  56. FILE    *ser_rd_fp = NULL;
  57. FILE    *ser_wr_fp = NULL;
  58.  
  59. /*
  60.  * getserverbyfile    Get the name of a server from a named file.
  61.  *            Handle white space and comments.
  62.  *            Use NNTPSERVER environment variable if set.
  63.  *
  64.  *    Parameters:    "file" is the name of the file to read.
  65.  *
  66.  *    Returns:    Pointer to static data area containing the
  67.  *            first non-ws/comment line in the file.
  68.  *            NULL on error (or lack of entry in file).
  69.  *
  70.  *    Side effects:    None.
  71.  */
  72.  
  73. char *
  74. getserverbyfile(file)
  75. char    *file;
  76. {
  77.     register FILE    *fp;
  78.     register char    *cp;
  79.     static char    buf[256];
  80.     char        *index();
  81.     char        *getenv();
  82.     char        *strcpy();
  83.  
  84.     if (cp = getenv("NNTPSERVER")) {
  85.         (void) strcpy(buf, cp);
  86.         return (buf);
  87.     }
  88.  
  89.     if (file == NULL)
  90.         return (NULL);
  91.  
  92.     fp = fopen(file, "r");
  93.     if (fp == NULL)
  94.         return (NULL);
  95.  
  96.     while (fgets(buf, sizeof (buf), fp) != NULL) {
  97.         if (*buf == '\n' || *buf == '#')
  98.             continue;
  99.         cp = index(buf, '\n');
  100.         if (cp)
  101.             *cp = '\0';
  102.         (void) fclose(fp);
  103.         return (buf);
  104.     }
  105.  
  106.     (void) fclose(fp);
  107.     return (NULL);             /* No entry */
  108. }
  109.  
  110.  
  111. /*
  112.  * server_init  Get a connection to the remote news server.
  113.  *
  114.  *    Parameters:    "machine" is the machine to connect to.
  115.  *
  116.  *    Returns:    -1 on error
  117.  *            server's initial response code on success.
  118.  *
  119.  *    Side effects:    Connects to server.
  120.  *            "ser_rd_fp" and "ser_wr_fp" are fp's
  121.  *            for reading and writing to server.
  122.  */
  123.  
  124. server_init(machine)
  125. char    *machine;
  126. {
  127.     int    sockt_rd, sockt_wr;
  128.     char    line[256];
  129.     char    *index();
  130. #ifdef DECNET
  131.     char    *cp;
  132.  
  133.     cp = index(machine, ':');
  134.  
  135.     if (cp && cp[1] == ':') {
  136.         *cp = '\0';
  137.         sockt_rd = get_dnet_socket(machine);
  138.     } else
  139.         sockt_rd = get_tcp_socket(machine);
  140. #else
  141.     sockt_rd = get_tcp_socket(machine);
  142. #endif
  143.  
  144.     if (sockt_rd < 0)
  145.         return (-1);
  146.  
  147.     /*
  148.      * Now we'll make file pointers (i.e., buffered I/O) out of
  149.      * the socket file descriptor.  Note that we can't just
  150.      * open a fp for reading and writing -- we have to open
  151.      * up two separate fp's, one for reading, one for writing.
  152.      */
  153.  
  154.     if ((ser_rd_fp = fdopen(sockt_rd, "r")) == NULL) {
  155.         perror("server_init: fdopen #1");
  156.         return (-1);
  157.     }
  158.  
  159.     sockt_wr = dup(sockt_rd);
  160.     if ((ser_wr_fp = fdopen(sockt_wr, "w")) == NULL) {
  161.         perror("server_init: fdopen #2");
  162.         ser_rd_fp = NULL;        /* from above */
  163.         return (-1);
  164.     }
  165.  
  166.     /* Now get the server's signon message */
  167.  
  168.     (void) get_server(line, sizeof(line));
  169.     return (atoi(line));
  170. }
  171.  
  172.  
  173. /*
  174.  * get_tcp_socket -- get us a socket connected to the news server.
  175.  *
  176.  *    Parameters:    "machine" is the machine the server is running on.
  177.  *
  178.  *    Returns:    Socket connected to the news server if
  179.  *            all is ok, else -1 on error.
  180.  *
  181.  *    Side effects:    Connects to server.
  182.  *
  183.  *    Errors:        Printed via perror.
  184.  */
  185.  
  186. get_tcp_socket(machine)
  187. char    *machine;
  188. {
  189.     int    s;
  190.     struct    sockaddr_in sin;
  191. #ifndef EXCELAN
  192.     struct    servent *getservbyname(), *sp;
  193.     struct    hostent *gethostbyname(), *hp;
  194. #ifdef h_addr
  195.     int    x = 0;
  196.     register char **cp;
  197. #endif h_addr
  198.  
  199.     if ((sp = getservbyname("nntp", "tcp")) ==  NULL) {
  200.         fprintf(stderr, "nntp/tcp: Unknown service.\n");
  201.         return (-1);
  202.     }
  203.  
  204.        /*
  205.         * Name resolution doesn't quite go as far as it should.  Take things
  206.         * one stage further to allow nnn.nnn.nnn.nnn addresses if all else
  207.         * fails.
  208.         */
  209.        if( (hp = gethostbyname( machine ) ) == NULL ) {
  210.                unsigned long inet_addr();
  211.                static struct hostent def;
  212.                static struct in_addr defaddr;
  213.                static char *alist[1];
  214.                static char namebuf[ 256 ];
  215.                defaddr.s_addr = inet_addr( machine );
  216.                if( defaddr.s_addr != -1 ) {
  217.                        strcpy( namebuf, machine );
  218.                        def.h_name = namebuf;
  219. #ifdef h_addr
  220.                        def.h_addr_list = alist;
  221. #endif
  222.                        def.h_addr = (char *)&defaddr;
  223.                        def.h_length = sizeof( struct in_addr );
  224.                        def.h_addrtype = AF_INET;
  225.                        def.h_aliases = 0;
  226.                        hp = &def;
  227.                }
  228.        }
  229.        if (hp == NULL) {
  230.         fprintf(stderr, "%s: Unknown host.\n", machine);
  231.         return (-1);
  232.     }
  233.  
  234.     bzero((char *) &sin, sizeof(sin));
  235.     sin.sin_family = hp->h_addrtype;
  236.     sin.sin_port = sp->s_port;
  237. #else EXCELAN
  238.     bzero((char *) &sin, sizeof(sin));
  239.     sin.sin_family = AF_INET;
  240.     sin.sin_port = htons(IPPORT_NNTP);
  241. #endif EXCELAN
  242.  
  243.     /*
  244.      * The following is kinda gross.  The name server under 4.3
  245.      * returns a list of addresses, each of which should be tried
  246.      * in turn if the previous one fails.  However, 4.2 hostent
  247.      * structure doesn't have this list of addresses.
  248.      * Under 4.3, h_addr is a #define to h_addr_list[0].
  249.      * We use this to figure out whether to include the NS specific
  250.      * code...
  251.      */
  252.  
  253. #ifdef    h_addr
  254.  
  255.     /* get a socket and initiate connection -- use multiple addresses */
  256.  
  257.     for (cp = hp->h_addr_list; cp && *cp; cp++) {
  258.         s = socket(hp->h_addrtype, SOCK_STREAM, 0);
  259.         if (s < 0) {
  260.             perror("socket");
  261.             return (-1);
  262.         }
  263.             bcopy(*cp, (char *)&sin.sin_addr, hp->h_length);
  264.  
  265.         if (x < 0)
  266.             fprintf(stderr, "trying %s\n", inet_ntoa(sin.sin_addr));
  267.         x = connect(s, (struct sockaddr *)&sin, sizeof (sin));
  268.         if (x == 0)
  269.             break;
  270.                 fprintf(stderr, "connection to %s: ", inet_ntoa(sin.sin_addr));
  271.         perror("");
  272.         (void) close(s);
  273.     }
  274.     if (x < 0) {
  275.         fprintf(stderr, "giving up...\n");
  276.         return (-1);
  277.     }
  278. #else    /* no name server */
  279. #ifdef EXCELAN
  280.     if ((s = rresvport(SO_KEEPALIVE)) < 0)
  281.     {
  282.         /* Get the socket */
  283.         perror("socket");
  284.         return (-1);
  285.     }
  286.     /* set up addr for the connect */
  287.     sin.sin_addr.s_addr = rhost(machine);
  288.     if (sin.sin_addr.s_addr < 0){
  289.         fprintf(stderr, "%s: Unknown host.\n", machine);
  290.         return (-1);
  291.     }
  292.     /* And then connect */
  293.  
  294.     if (connect(s, &sin) < 0) {
  295.         perror("connect");
  296.         (void) close(s);
  297.         return (-1);
  298.     }
  299. #else not EXCELAN
  300.     if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
  301.         perror("socket");
  302.         return (-1);
  303.     }
  304.  
  305.     /* And then connect */
  306.  
  307.     bcopy(hp->h_addr, (char *) &sin.sin_addr, hp->h_length);
  308.     if (connect(s, (struct sockaddr *) &sin, sizeof(sin)) < 0) {
  309.         perror("connect");
  310.         (void) close(s);
  311.         return (-1);
  312.     }
  313.  
  314. #endif not EXCELAN
  315. #endif
  316.  
  317.     return (s);
  318. }
  319.  
  320. #ifdef DECNET
  321. /*
  322.  * get_dnet_socket -- get us a socket connected to the news server.
  323.  *
  324.  *    Parameters:    "machine" is the machine the server is running on.
  325.  *
  326.  *    Returns:    Socket connected to the news server if
  327.  *            all is ok, else -1 on error.
  328.  *
  329.  *    Side effects:    Connects to server.
  330.  *
  331.  *    Errors:        Printed via nerror.
  332.  */
  333.  
  334. get_dnet_socket(machine)
  335. char    *machine;
  336. {
  337.     int    s, area, node;
  338.     struct    sockaddr_dn sdn;
  339.     struct    nodeent *getnodebyname(), *np;
  340.  
  341.     bzero((char *) &sdn, sizeof(sdn));
  342.  
  343.     switch (s = sscanf( machine, "%d%*[.]%d", &area, &node )) {
  344.         case 1:
  345.             node = area;
  346.             area = 0;
  347.         case 2:
  348.             node += area*1024;
  349.             sdn.sdn_add.a_len = 2;
  350.             sdn.sdn_family = AF_DECnet;
  351.             sdn.sdn_add.a_addr[0] = node % 256;
  352.             sdn.sdn_add.a_addr[1] = node / 256;
  353.             break;
  354.         default:
  355.             if ((np = getnodebyname(machine)) == NULL) {
  356.                 fprintf(stderr,
  357.                     "%s: Unknown host.\n", machine);
  358.                 return (-1);
  359.             } else {
  360.                 bcopy(np->n_addr,
  361.                     (char *) sdn.sdn_add.a_addr,
  362.                     np->n_length);
  363.                 sdn.sdn_add.a_len = np->n_length;
  364.                 sdn.sdn_family = np->n_addrtype;
  365.             }
  366.             break;
  367.     }
  368.     sdn.sdn_objnum = 0;
  369.     sdn.sdn_flags = 0;
  370.     sdn.sdn_objnamel = strlen("NNTP");
  371.     bcopy("NNTP", &sdn.sdn_objname[0], sdn.sdn_objnamel);
  372.  
  373.     if ((s = socket(AF_DECnet, SOCK_STREAM, 0)) < 0) {
  374.         nerror("socket");
  375.         return (-1);
  376.     }
  377.  
  378.     /* And then connect */
  379.  
  380.     if (connect(s, (struct sockaddr *) &sdn, sizeof(sdn)) < 0) {
  381.         nerror("connect");
  382.         close(s);
  383.         return (-1);
  384.     }
  385.  
  386.     return (s);
  387. }
  388. #endif
  389.  
  390.  
  391.  
  392. /*
  393.  * handle_server_response
  394.  *
  395.  *    Print some informative messages based on the server's initial
  396.  *    response code.  This is here so inews, rn, etc. can share
  397.  *    the code.
  398.  *
  399.  *    Parameters:    "response" is the response code which the
  400.  *            server sent us, presumably from "server_init",
  401.  *            above.
  402.  *            "server" is the news server we got the
  403.  *            response code from.
  404.  *
  405.  *    Returns:    -1 if the error is fatal (and we should exit).
  406.  *            0 otherwise.
  407.  *
  408.  *    Side effects:    None.
  409.  */
  410.  
  411. handle_server_response(response, server)
  412. int    response;
  413. char    *server;
  414. {
  415.     switch (response) {
  416.     case OK_NOPOST:        /* fall through */
  417.             printf(
  418.     "NOTE: This machine does not have permission to post articles.\n");
  419.         printf(
  420.     "      Please don't waste your time trying.\n\n");
  421.  
  422.     case OK_CANPOST:
  423.         return (0);
  424.         break;
  425.  
  426.     case ERR_ACCESS:
  427.         printf(
  428.    "This machine does not have permission to use the %s news server.\n",
  429.         server);
  430.         return (-1);
  431.         break;
  432.  
  433.     default:
  434.         printf("Unexpected response code from %s news server: %d\n",
  435.             server, response);
  436.         return (-1);
  437.         break;
  438.     }
  439.     /*NOTREACHED*/
  440. }
  441.  
  442.  
  443. /*
  444.  * put_server -- send a line of text to the server, terminating it
  445.  * with CR and LF, as per ARPA standard.
  446.  *
  447.  *    Parameters:    "string" is the string to be sent to the
  448.  *            server.
  449.  *
  450.  *    Returns:    Nothing.
  451.  *
  452.  *    Side effects:    Talks to the server.
  453.  *
  454.  *    Note:        This routine flushes the buffer each time
  455.  *            it is called.  For large transmissions
  456.  *            (i.e., posting news) don't use it.  Instead,
  457.  *            do the fprintf's yourself, and then a final
  458.  *            fflush.
  459.  */
  460.  
  461. void
  462. put_server(string)
  463. char *string;
  464. {
  465. #ifdef DEBUG
  466.     fprintf(stderr, ">>> %s\n", string);
  467. #endif
  468.     fprintf(ser_wr_fp, "%s\r\n", string);
  469.     (void) fflush(ser_wr_fp);
  470. }
  471.  
  472.  
  473. /*
  474.  * get_server -- get a line of text from the server.  Strips
  475.  * CR's and LF's.
  476.  *
  477.  *    Parameters:    "string" has the buffer space for the
  478.  *            line received.
  479.  *            "size" is the size of the buffer.
  480.  *
  481.  *    Returns:    -1 on error, 0 otherwise.
  482.  *
  483.  *    Side effects:    Talks to server, changes contents of "string".
  484.  */
  485.  
  486. get_server(string, size)
  487. char    *string;
  488. int    size;
  489. {
  490.     register char *cp;
  491.     char    *index();
  492.  
  493.     if (fgets(string, size, ser_rd_fp) == NULL)
  494.         return (-1);
  495.  
  496.     if ((cp = index(string, '\r')) != NULL)
  497.         *cp = '\0';
  498.     else if ((cp = index(string, '\n')) != NULL)
  499.         *cp = '\0';
  500. #ifdef DEBUG
  501.     fprintf(stderr, "<<< %s\n", string);
  502. #endif
  503.  
  504.     return (0);
  505. }
  506.  
  507.  
  508. /*
  509.  * close_server -- close the connection to the server, after sending
  510.  *        the "quit" command.
  511.  *
  512.  *    Parameters:    None.
  513.  *
  514.  *    Returns:    Nothing.
  515.  *
  516.  *    Side effects:    Closes the connection with the server.
  517.  *            You can't use "put_server" or "get_server"
  518.  *            after this routine is called.
  519.  */
  520.  
  521. void
  522. close_server()
  523. {
  524.     char    ser_line[256];
  525.  
  526.     if (ser_wr_fp == NULL || ser_rd_fp == NULL)
  527.         return;
  528.  
  529.     put_server("QUIT");
  530.     (void) get_server(ser_line, sizeof(ser_line));
  531.  
  532.     (void) fclose(ser_wr_fp);
  533.     (void) fclose(ser_rd_fp);
  534. }
  535.  
  536.